Conversation
The `bun.lock` file was deleted to declutter the repository and avoid potential dependency conflicts or outdated lock versions. This change ensures that dependency resolution relies on package definitions instead of pre-locked constraints.
Replace `generateEmailBody` with the updated and more robust `generateEmailBodyV2` in the actions layer. Adjust type annotations and streamline parameters to enhance clarity and maintainability.
|
@dakdevs is attempting to deploy a commit to the Zero Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis update introduces a comprehensive writing style analysis and adaptation system for email generation. A new database table and service layer are added to store and update a "writing style matrix" for each email connection, capturing detailed stylistic metrics from sent emails. New prompt templates and AI utility functions enable generating email bodies that mimic the user's style, using advanced models and style-aware system prompts. The email sending workflow is extended to asynchronously update the style matrix after each sent message. Supporting changes include new dependencies, prompt functions, and minor code cleanups. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MailApp
participant AIService
participant StyleService
participant DB
User->>MailApp: Compose & Send Email
MailApp->>AIService: generateEmailBody(prompt, context, recipients, subject, userContext)
AIService->>StyleService: getWritingStyleMatrix(connectionId)
StyleService->>DB: Fetch style matrix
DB-->>StyleService: Return style matrix
StyleService-->>AIService: Style matrix
AIService->>AIService: Generate email body using style-aware prompt
AIService-->>MailApp: AI-generated email body
MailApp->>MailApp: Send email via driver
MailApp-->>User: Email sent confirmation
MailApp->>StyleService: updateWritingStyleMatrix(connectionId, emailBody) (async)
StyleService->>DB: Update style matrix with new metrics
DB-->>StyleService: Confirm update
Possibly related PRs
Poem
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Deleted unused files in the mail app to clean up the repository. Updated the root `.npmrc` to enforce exact version saving for better dependency management. These changes improve clarity and maintainability.
There was a problem hiding this comment.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
apps/mail/.node-version (1)
1-2: 💡 Verification agent🧩 Analysis chain
Verify compatibility with Node.js 22
Node.js 22 is a very recent version (released in April 2024). Ensure that:
- Your critical dependencies are compatible with this version
- Your deployment environments support Node.js 22
- The team is aware of any breaking changes from previous Node.js versions
🏁 Script executed:
#!/bin/bash # Check if there are any package.json files that might be affected echo "Checking for package.json files in the mail app:" find apps/mail -name "package.json" -type f | grep -v "node_modules" # Check for engines field in package.json files echo -e "\nChecking for Node.js engine requirements in package.json:" find apps/mail -name "package.json" -type f -exec grep -l "\"engines\"" {} \; | xargs -I{} bash -c 'echo "File: {}"; cat {} | jq ".engines"' # Look for CI/CD configuration files to check deployment environments echo -e "\nChecking CI/CD configurations:" find . -name "*.yml" -o -name "*.yaml" | grep -E "github|gitlab|azure|jenkins|circleci|travis" | xargs grep -l "node" 2>/dev/nullLength of output: 722
🏁 Script executed:
#!/bin/bash echo "Scanning CI workflows for Node.js version configuration…" echo -e "\n1. Checking for actions/setup-node usage:" grep -R "actions/setup-node" -n .github/workflows/*.yml || echo "→ No setup-node action found." echo -e "\n2. Checking for explicit node-version fields:" grep -R "node-version" -n .github/workflows/*.yml || echo "→ No node-version field found." echo -e "\n3. Checking for matrix definitions with node:" grep -R "matrix" -n .github/workflows/*.yml | grep -C3 "node" || echo "→ No node matrix found."Length of output: 992
Ensure Node.js 22 Compatibility and Pin Version
Please update your configuration to explicitly target and verify Node.js 22:
• In apps/mail/package.json, add an “engines” field to lock to Node 22 (e.g.
"engines": { "node": ">=22 <23" })
• In your GitHub workflows (.github/workflows/ci.yml & main.yml), replacenode-version: latestwithnode-version: 22.xto guarantee CI runs on Node 22
• Confirm all critical dependencies have been tested on Node 22 and that your deployment environments support it
• Document any known breaking changes for the team’s awareness
🧹 Nitpick comments (6)
apps/mail/actions/ai.ts (2)
4-4: Remove unused import to avoid TS--noUnusedLocalsbreakage
generateEmailBodyis no longer referenced after the switch togenerateEmailBodyV2.-import { generateEmailBody, generateEmailBodyV2, generateSubjectForEmail } from '@/lib/ai'; +import { generateEmailBodyV2, generateSubjectForEmail } from '@/lib/ai';
74-85: Early guard duplicates work – consider returning earlyYou test for an empty
responseBodydirectly after assigning a default'', which will always be falsy. The guard therefore always triggers. Either drop the default or invert the check.-const responseBody = response.body ?? ''; -if (!responseBody) { +const responseBody = response.content?.trim() ?? ''; +if (responseBody === '') {apps/mail/services/writing-style-service.ts (2)
165-174:updateStatlacks sample-count tracking → cannot derive variance laterYou keep running
m2but never recordn, so computing variance elsewhere asm2 / (n-1)won’t be possible.
Either:
- Store
countalongsidemean&m2, or- Infer it from
numMessageswhen reading, but document that contract.export type RunningStat = { mean: number; m2: number; n: number; // <-- add }
129-153: Coverage algorithm may drop the last needed element
takeWhilestops before the predicate fails, so the last element that pushes coverage ≥ 0.95 is excluded.
Switch toreduceor include the current element before evaluating coverage.- takeWhile(([_, count]) => { - running += count - return running / total < coverage - }), + takeWhile(([_, count]) => { + running += count + return running / total <= coverage // include boundary + }),apps/mail/.npmrc (1)
1-6: Risky npm flags – please confirm necessity
legacy-peer-deps=trueand the twopackage-manager-strict*flags disable critical safety nets.
This can mask incompatible versions at install-time and make deterministic builds harder.Recommend enabling strictness in CI (at least) or pinning peer ranges explicitly.
apps/mail/lib/ai.ts (1)
106-166: Duplicate post-processing logic – extract to shared util
postProcessMessageduplicates almost line-for-line the cleaning logic present further down in the legacygenerateEmailBody. Maintaining two copies increases bug-fix surface and drift risk.Refactor into a single helper (e.g.,
sanitizeGeneratedBody(text): AIBodyResponse[]) and invoke it from both functions.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
apps/mail/.node-version(1 hunks)apps/mail/.npmrc(1 hunks)apps/mail/.tool-versions(1 hunks)apps/mail/actions/ai.ts(5 hunks)apps/mail/actions/send.ts(2 hunks)apps/mail/lib/ai.ts(11 hunks)apps/mail/lib/prompts.ts(2 hunks)apps/mail/services/writing-style-service.ts(1 hunks)package.json(1 hunks)packages/db/src/schema.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/db/src/schema.ts (1)
apps/mail/services/writing-style-service.ts (1)
WritingStyleMatrix(221-229)
apps/mail/actions/ai.ts (1)
apps/mail/lib/ai.ts (1)
generateEmailBodyV2(41-104)
apps/mail/lib/prompts.ts (1)
apps/mail/services/writing-style-service.ts (1)
WritingStyleMatrix(221-229)
🔇 Additional comments (4)
apps/mail/actions/ai.ts (1)
49-57:Details
❌ Incorrect review comment
Type mismatch:
AIBodyResponsedefinescontent, but the code expectsbody
generateEmailBodyV2returnsAIBodyResponse[]where each element hascontent; yet lines 69-76 accessresponse.body.
This will compile only if you’ve disabled strict type-checking or ifpostProcessMessagereturns a different shape than declared. In either case one of them is wrong.-const responseBody = response.body ?? ''; +const responseBody = (response.content ?? '').toString();Update either the interface or the post-processing helper so that shapes align, then adjust every consumer accordingly.
🏁 Script executed:
#!/bin/bash set -e echo "=== Searching for generateEmailBodyV2 definition and usage ===" rg "generateEmailBodyV2" -n echo echo "=== Searching for AIBodyResponse interface or type declaration ===" rg "AIBodyResponse" -n echo echo "=== Searching for postProcessMessage definition ===" rg "postProcessMessage" -nLength of output: 1298
🏁 Script executed:
#!/bin/bash set -e echo "=== apps/mail/lib/ai.ts: Definitions and generateEmailBodyV2 ===" sed -n '1,200p' apps/mail/lib/ai.ts echo echo "=== apps/mail/actions/ai.ts: Imported types, local interface, and usage ===" sed -n '1,100p' apps/mail/actions/ai.tsLength of output: 9693
Ignore the reported type mismatch – the interfaces are distinct per module
The
AIBodyResponseinapps/mail/lib/ai.tsdefines abodyfield, which is whatgenerateEmailBodyV2returns and what the action layer correctly consumes viaresponse.body. The action file deliberately declares its ownAIBodyResponse(withcontentandjsonContent) as the return type ofgenerateAIEmailBody. There’s no misalignment in the shapes that would break strict mode on either side.No changes are required to
generateEmailBodyV2,postProcessMessage, or the consuming code.Likely an incorrect or invalid review comment.
apps/mail/.tool-versions (1)
1-2: Consistent with .node-version fileThis file properly aligns with the Node.js version (22) specified in the
.node-versionfile. The.tool-versionsfile is used by the asdf version manager to specify tool versions, while.node-versionis used by other version managers like nvm.packages/db/src/schema.ts (2)
1-4: LGTM - Import for the WritingStyleMatrix typeThe import for the WritingStyleMatrix type is correctly added to support the new database table schema.
134-147:Details
✅ Verification successful
Well-structured database schema for the writing style matrix
The table schema is well-defined with proper references, data types, and constraints. The primary key is correctly set up on the connectionId column.
A few observations:
- The schema properly references the connection.id as a foreign key
- The style column uses jsonb type with appropriate type safety via $type
- The updatedAt column has an automatic update trigger
🏁 Script executed:
#!/bin/bash # Verify that the WritingStyleMatrix type is correctly defined echo "Checking WritingStyleMatrix type definition:" grep -A 15 "export type WritingStyleMatrix" apps/mail/services/writing-style-service.ts # Check for code that will update this table echo -e "\nChecking for code that updates the writing style matrix:" rg "writingStyleMatrix" --type tsLength of output: 1597
✅ Approve WritingStyleMatrix schema and usage
- Verified that
export type WritingStyleMatrixinapps/mail/services/writing-style-service.tsmatches the JSONBstylecolumn fields.- Confirmed insert and update operations on
writingStyleMatrixinapps/mail/services/writing-style-service.ts.- Foreign key reference to
connection.id, JSONB$type, andupdatedAtauto-update trigger are all correctly configured.No changes required.
Removed redundant dependencies and imports to streamline the codebase. Updated versions and formatting in package files while improving readability and maintainability of the AI-related functionality.
Wrap the writing style matrix update in a try-catch block to ensure failures are logged without crashing the process. This improves robustness and helps in debugging issues when the update fails.
Updated the environment variable check to validate `OPENAI_API_KEY` instead of `GROQ_API_KEY`. This ensures compatibility with the updated API configuration and avoids potential misconfigurations.
Replaces `generateEmailBodyV2` with `generateEmailBody`, consolidating logic and improving error handling. Simplifies code for better maintainability while ensuring consistent functionality during AI-driven email generation.
Refactored AI prompt generation to exclude conversation history logic. Simplifies the code by directly appending the user prompt without wrapping in conversation history tags or processing previous messages. This improves maintainability and focuses solely on the current prompt context.
Replaced the raw user prompt with an escaped version to prevent potential issues with invalid or unsafe XML characters. This ensures message formatting remains correct and improves overall robustness.
Previously, totals were always initialized to 1 regardless of whether values existed. This update ensures totals are only set to 1 when corresponding values are present, improving accuracy in metrics calculation.
This refactor eliminates the unused `conversationId` and `signatureHash` parameters and related logic across multiple files. Additionally, it streamlines the prompt definitions and improves the initialization of metrics calculations for writing style analysis.
There was a problem hiding this comment.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
apps/mail/lib/ai.ts (1)
32-40: 🛠️ Refactor suggestion
conversationHistoriesis never mutated – feature is inertThe cache is allocated but nothing writes to it, so conversation context is lost and memory is wasted.
Either remove the structure or push the user/assistant messages into it after each generation.
♻️ Duplicate comments (1)
apps/mail/lib/prompts.ts (1)
162-165:⚠️ Potential issueEscape untrusted dynamic context to prevent prompt-injection
currentSubject,currentDraft, and therecipientslist are injected verbatim into the pseudo-XML envelope.
If any of these contain<,>,&, quotes, or XML-like substrings, the prompt becomes malformed and opens the door to prompt-injection.-const currentSubjectContent = currentSubject ? `\n\n<current_subject>${currentSubject}</current_subject>\n\n` : ''; -const currentDraftContent = currentDraft ? `\n\n<current_draft>${currentDraft}</current_draft>\n\n` : ''; -const recipientsContent = recipients ? `\n\n<recipients>${recipients.join(', ')}</recipients>\n\n` : ''; +const currentSubjectContent = currentSubject + ? `\n\n<current_subject>${escapeXml(currentSubject)}</current_subject>\n\n` + : ''; +const currentDraftContent = currentDraft + ? `\n\n<current_draft>${escapeXml(currentDraft)}</current_draft>\n\n` + : ''; +const recipientsContent = recipients && recipients.length + ? `\n\n<recipients>${recipients.map(escapeXml).join(', ')}</recipients>\n\n` + : '';
🧹 Nitpick comments (4)
apps/mail/lib/prompts.ts (1)
185-195: Escape serialized JSON style profile before embedding
styleProfileJSONmay contain>,<, or&via user greetings/sign-offs, breaking the surrounding XML.
Escape it just likeuserName:-const styleProfileJSON = JSON.stringify(styleProfile, null, 2); +const styleProfileJSON = escapeXml(JSON.stringify(styleProfile, null, 2));apps/mail/services/writing-style-service.ts (1)
201-204: RunningStat lacks the email count – variance cannot be recoveredYou store only
meanandm2. To compute variance later you’ll needn(numMessages).
Either embedcountinRunningStator always passnumMessagesalongside the stat.apps/mail/lib/ai.ts (2)
42-53:userContextdeclared in the type but not destructuredThe parameter list omits
userContext; callers can still pass it silently, causing confusion.
Add it to the destructuring list or drop it from the signature.
134-140: Over-zealous unsafe pattern may block valid addressesThe regex flags any
<…>which matches common email address formats (<john@example.com>).
Consider a narrower pattern that targets HTML tags (/<\s*(script|style|[a-z]+[^>]*)>/i) instead of any angle-bracket pair.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/mail/actions/ai.ts(4 hunks)apps/mail/actions/send.ts(2 hunks)apps/mail/components/create/ai-assistant.tsx(2 hunks)apps/mail/lib/ai.ts(7 hunks)apps/mail/lib/prompts.ts(2 hunks)apps/mail/services/writing-style-service.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/mail/components/create/ai-assistant.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/mail/actions/send.ts
- apps/mail/actions/ai.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/mail/lib/prompts.ts (1)
apps/mail/services/writing-style-service.ts (1)
WritingStyleMatrix(213-221)
apps/mail/services/writing-style-service.ts (3)
packages/db/src/index.ts (1)
db(17-17)apps/mail/lib/ai.ts (1)
extractStyleMatrix(246-302)packages/db/src/schema.ts (1)
writingStyleMatrix(134-147)
Added metrics for slang usage, contractions, subject casualness, and more to provide deeper insights into writing style. Updated prompts and service logic to incorporate these metrics while maintaining clear documentation and examples. Improved consistency and expanded guidelines for style extraction.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
apps/mail/services/writing-style-service.ts (3)
152-157: Fix thetakeTopCoveragefunction to include the threshold element.The current implementation terminates too early and never reaches the requested coverage. Since the predicate runs after
runningis incremented and uses a strict<, the loop exits while coverage is still below the threshold.-takeWhile(([_, count]) => { - running += count - return running / total < coverage -}), +reduce((acc, [key, count]) => { + if (running / total >= coverage) return acc; + running += count; + acc[key] = count; + return acc; +}, {} as Record<string, number>),
113-118: Recalculate total after trimming counts.After applying
takeTopCoverage/takeTopK, you're dropping low-frequency entries but still using the oldgreetingTotalto compute probabilities. This makespGreetinconsistent with the sum ofgreetingCounts.-newStyle.greetingCounts = TAKE_TYPE === 'coverage' - ? takeTopCoverage(newStyle.greetingCounts) - : takeTopK(newStyle.greetingCounts) - -// Record the total number of greetings -newStyle.greetingTotal = newStyle.greetingTotal + 1 -newStyle.pGreet = newStyle.greetingTotal / newNumMessages +newStyle.greetingCounts = TAKE_TYPE === 'coverage' + ? takeTopCoverage(newStyle.greetingCounts) + : takeTopK(newStyle.greetingCounts) + +// Recompute total and probability from the trimmed counts +const updatedGreetingTotal = Object.values(newStyle.greetingCounts) + .reduce((sum, count) => sum + count, 0) +newStyle.greetingTotal = updatedGreetingTotal +newStyle.pGreet = updatedGreetingTotal / newNumMessages
125-130: 🛠️ Refactor suggestionApply the same fix for signOff counts.
The same issue applies to
signOffCounts. After trimming, you need to recalculate the total.-newStyle.signOffCounts = TAKE_TYPE === 'coverage' - ? takeTopCoverage(newStyle.signOffCounts) - : takeTopK(newStyle.signOffCounts) - -// Record the total number of sign offs -newStyle.signOffTotal = newStyle.signOffTotal + 1 -newStyle.pSign = newStyle.signOffTotal / newNumMessages +newStyle.signOffCounts = TAKE_TYPE === 'coverage' + ? takeTopCoverage(newStyle.signOffCounts) + : takeTopK(newStyle.signOffCounts) + +// Recompute total and probability from the trimmed counts +const updatedSignOffTotal = Object.values(newStyle.signOffCounts) + .reduce((sum, count) => sum + count, 0) +newStyle.signOffTotal = updatedSignOffTotal +newStyle.pSign = updatedSignOffTotal / newNumMessagesapps/mail/lib/ai.ts (1)
86-98: Missing conversation history update.Unlike the legacy implementation, this code doesn't update
conversationHistories, so any context from previous interactions is lost.Add code to initialize and update conversation histories:
const { text, } = await generateText({ model: openai('gpt-4o'), system: systemPrompt, prompt: finalPrompt, maxTokens: 600, temperature: 0.35, // controlled creativity frequencyPenalty: 0.2, // dampen phrase repetition presencePenalty: 0.1, // nudge the model to add fresh info maxRetries: 1, }) + + // Record conversation history + if (!conversationHistories[userId]) { + conversationHistories[userId] = {} + } + + const conversationId = generateConversationId(prompt) // Or however you want to track conversations + if (!conversationHistories[userId][conversationId]) { + conversationHistories[userId][conversationId] = [] + } + + conversationHistories[userId][conversationId].push({ role: 'user', content: prompt }) + conversationHistories[userId][conversationId].push({ role: 'assistant', content: text })
🧹 Nitpick comments (3)
apps/mail/services/writing-style-service.ts (1)
57-89: Add error handling for the service operation.The
updateWritingStyleMatrixfunction lacks specific error handling. IfextractStyleMatrixor database operations fail, errors will propagate to the caller, potentially causing unhandled exceptions.Consider adding explicit error handling:
export const updateWritingStyleMatrix = async (connectionId: string, emailBody: string) => { + try { const emailStyleMatrix = await extractStyleMatrix(emailBody) await db.transaction(async (tx) => { // ... existing implementation }) + } catch (error) { + console.error('Failed to update writing style matrix:', error) + // Either rethrow or handle gracefully depending on requirements + throw error + } }apps/mail/lib/ai.ts (2)
143-157: Consider expanding refusal detection patterns.The current list of refusal patterns is good but could be expanded to catch more variations.
Consider adding more common refusal patterns:
const isRefusal = lowerBody.includes("i cannot") || lowerBody.includes("i'm unable to") || lowerBody.includes("i am unable to") || lowerBody.includes("as an ai") || lowerBody.includes("my purpose is to assist") || lowerBody.includes("violates my safety guidelines") || + lowerBody.includes("i don't have the ability") || + lowerBody.includes("i'm not able to") || + lowerBody.includes("i'm not designed to") || + lowerBody.includes("against my programming") || + lowerBody.includes("ethical concerns") || lowerBody.includes("sorry, i can only assist with email body");
196-197: Consider more deterministic subject generation.For subject generation, you're using a relatively high temperature (0.5) compared to the email body generation (0.35) and style extraction (0). For consistency in subject lines, you might consider lowering this.
const { completion: generatedSubjectRaw } = await generateCompletions({ model: 'gpt-4', // Using the more capable model systemPrompt: systemPrompt, prompt: subjectPrompt, - temperature: 0.5, + temperature: 0.35, // Same temperature as email body for consistency });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/mail/lib/ai.ts(7 hunks)apps/mail/lib/prompts.ts(2 hunks)apps/mail/services/writing-style-service.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/mail/lib/prompts.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/mail/services/writing-style-service.ts (3)
packages/db/src/index.ts (1)
db(17-17)apps/mail/lib/ai.ts (1)
extractStyleMatrix(246-314)packages/db/src/schema.ts (1)
writingStyleMatrix(134-147)
🔇 Additional comments (7)
apps/mail/services/writing-style-service.ts (3)
189-204: LGTM: Properly handling nullable greetings and sign-offs.The initialization logic correctly sets
greetingTotalandsignOffTotalto 0 when their respective fields are null, addressing a previously identified issue.
13-43: Thorough metric key documentation.The extensive comments for each metric key provide excellent context for understanding what the writing style service is tracking, which improves maintainability.
171-180: LGTM: Efficient running statistics implementation.The
updateStatfunction correctly implements Welford's online algorithm for computing running mean and variance, which is numerically stable and memory-efficient for tracking statistics across many emails.apps/mail/lib/ai.ts (4)
55-57: Fix for API key check: using OpenAI instead of Groq.You've correctly fixed the API key check to use
OPENAI_API_KEYinstead ofGROQ_API_KEY, which aligns with the OpenAI model being used (openai('gpt-4o')).
134-140: Robust safety checks for generated content.Great implementation of safety checks to detect HTML, code blocks, or other potentially unsafe content in the generated response.
246-314: Excellent implementation of style extraction.The
extractStyleMatrixfunction is well-implemented with:
- Comprehensive schema validation using Zod
- Appropriate error handling for empty inputs
- Good model selection with mini variant for efficiency
- Normalization of greeting and sign-off values
- Clear typing and structure
73-77:Details
✅ Verification successful
Ensure writing style matrix property access is correct.
The service returns an object with
numMessagesandstylefields, wherestylecontains theWritingStyleMatrix. The current code assumes the matrix is directly accessible viawritingStyleMatrix.style.
🏁 Script executed:
#!/bin/bash # Verify the structure of the WritingStyleMatrix return echo "=== getWritingStyleMatrixForConnectionId signature ===" fd --type file "writing-style-service.ts" | xargs rg -n "export const getWritingStyleMatrixForConnectionId" -A 10Length of output: 569
No action needed – property access is correct
The
getWritingStyleMatrixForConnectionIdfunction returns an object with astylefield (alongsidenumMessages), so accessingwritingStyleMatrix.styleis exactly right.
Replaced the existing metrics calculation with Welford's algorithm for improved numerical accuracy and efficiency. Split metrics into mean-based, sum-based, and count-based categories, and adjusted initialization and update methods accordingly. Deprecated `subjectEmojiCount` and `subjectInformalityScore` while introducing metrics for greeting/sign-off presence.
| # don't show warnings if package versions don't match | ||
| strict-peer-dependencies=false | ||
| auto-install-peers=true | ||
| save-exact=true |
There was a problem hiding this comment.
Added this to auto-pin dependencies.
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
apps/mail/lib/ai.ts (1)
32-39: 🛠️ Refactor suggestion
conversationHistoriesis never mutated – feature is inertYou define an in-memory store but never push messages into it, so every call starts with an empty history.
Either:
- Remove the variable, or
- Persist user/assistant turns after
generateTextcompletes (see earlier review ongenerateEmailBodyV2).Neglecting this defeats multi-turn context and wastes memory.
♻️ Duplicate comments (1)
apps/mail/services/writing-style-service.ts (1)
170-174:takeTopCoveragestill stops one element short of the requested coverage
This was reported in an earlier review and remains unfixed.
See prior diff suggestion for the correct reducer-based implementation.
🧹 Nitpick comments (2)
apps/mail/services/writing-style-service.ts (1)
118-121: Emptyfor-loop is dead codeThe loop over
TOP_COUNTS_KEYSperforms no body work and can be removed.
Keeping it around is confusing and may hint at an unfinished implementation.apps/mail/lib/ai.ts (1)
47-52: UnuseduserContextparameter
userContextis accepted but ignored entirely. Delete the param or make use of it (e.g., pass the sender’s email/name into prompts).
Leaving dead interface surface invites bugs down the line.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/mail/lib/ai.ts(7 hunks)apps/mail/lib/prompts.ts(2 hunks)apps/mail/services/writing-style-service.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/mail/lib/prompts.ts
🔇 Additional comments (1)
apps/mail/services/writing-style-service.ts (1)
189-198:updateStatis unused – remove or integrateThere are no callers for
updateStat. Keeping unused code increases maintenance burden and confuses readers.
[ suggest_optional_refactor ]
Unify handling of greeting and signOff keys by leveraging TOP_COUNTS_KEYS. Simplify logic for updating and initializing style metrics, reducing redundancy. These changes improve maintainability and clarity of the service code.
The conversationHistory parameter was no longer being utilized and has been removed to clean up the code. This improves maintainability and reduces potential confusion for future updates.
The conversationHistories object was no longer being used and has been removed to clean up the code. This simplifies code maintenance and avoids potential confusion.
Replaced angle brackets with HTML entities to ensure proper rendering and standardized formatting of prompt instructions. Enhanced readability by aligning tone, sentence, and paragraph length guidelines for consistency.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/mail/lib/ai.ts (2)
50-51: Remove unnecessary await from headers() call.The
headers()function from next/headers is synchronous and doesn't return a Promise - awaiting it can cause the request to hang in Edge runtimes.- const headersList = await headers() + const headersList = headers()
64-68:⚠️ Potential issueFix the writingStyleMatrix property access.
The
writingStyleMatrix.styleproperty access appears incorrect - based on the definition in the writing style service, the whole object IS the style profile.- const systemPrompt = writingStyleMatrix ? - StyledEmailAssistantSystemPrompt(userName, writingStyleMatrix.style) : + const systemPrompt = writingStyleMatrix ? + StyledEmailAssistantSystemPrompt(userName, writingStyleMatrix) : EmailAssistantSystemPrompt(userName);
🧹 Nitpick comments (3)
apps/mail/lib/ai.ts (3)
125-131: Consider adding test for HTML sanitization.The safety check pattern is well-implemented, but consider adding a unit test to verify it catches all unsafe patterns you're concerned about.
237-307: Strong implementation of writing style extraction.The
extractStyleMatrixfunction is well designed with:
- Comprehensive style metrics extraction
- Proper schema validation using zod
- Appropriate error handling for empty content
- Good normalization of greeting and sign-off strings
Consider adding a caching mechanism if this function is called frequently, as it could be expensive in terms of API usage and latency.
242-296: Consider handling potential AI model errors.The
generateObjectcall could fail if the model struggles to extract certain metrics from unusual email content. Consider adding more specific error handling for this case.const { object, - } = await generateObject({ + } = await generateObject({ // ...existing configuration }) +} catch (error) { + console.error('Failed to extract style matrix:', error); + // Return default/empty style matrix or rethrow with more context + throw new Error(`Style extraction failed: ${error.message}`); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/mail/lib/ai.ts(7 hunks)apps/mail/lib/prompts.ts(2 hunks)apps/mail/services/writing-style-service.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/mail/lib/prompts.ts
- apps/mail/services/writing-style-service.ts
🔇 Additional comments (1)
apps/mail/lib/ai.ts (1)
46-47: LGTM: Environmental API key validation corrected.The code now properly checks for the OpenAI API key instead of Groq, which aligns with using the openai model in the implementation.
Enhanced formatting, structure, and style adaptation rules for better alignment with user metrics. Improved descriptions and examples to ensure consistent tone, readability, and engagement cues.
| after(async () => { | ||
| try { | ||
| console.warn('Saving writing style matrix...') | ||
| await updateWritingStyleMatrix(connection.id, message) | ||
| console.warn('Saved writing style matrix.') | ||
| } catch (error) { | ||
| console.error('Failed to save writing style matrix', error) | ||
| } | ||
| }) |
There was a problem hiding this comment.
This way once the email sends, the user gets feedback immediately while the style matrix gets update in the background.
| const conversationHistories: Record< | ||
| string, // userId | ||
| Record< | ||
| string, // conversationId | ||
| { role: 'user' | 'assistant' | 'system'; content: string }[] | ||
| > | ||
| > = {}; |
There was a problem hiding this comment.
Due to the server-less nature of the runtime, this wouldn't actually properly persist.
| }); | ||
| console.log(`AI Assistant (Body): Received completion for convId ${convId}:`, generatedBodyRaw); | ||
|
|
||
| // --- Post-processing: Remove common conversational prefixes --- |
There was a problem hiding this comment.
moved a lot of this to it's own function for now.
# Conflicts: # bun.lock
Introduces a new seeder framework to manage style matrices, including commands for seeding and resetting data. Enhances email summary updates with improved prompts and transaction handling for better performance and reliability.
# Conflicts: # packages/db/src/schema.ts
Switched to the "llama-3.1-8b-instant" model for text generation and increased max retries from 3 to 5 for improved reliability.
Deleted an extraneous blank line to improve code readability and consistency. This is a minor cleanup with no functional impact.
Refactored AI body generation by integrating LangChain's ChatGroq and updated JSON parsing logic for consistent schema handling. Enhanced the style-matrix seeding script with retry logic to improve resilience. Added stricter guidelines in prompts and updated dependencies for compatibility.
Renamed the seed-style-matrix command and related files to seed-style for consistency and simplicity. Updated `run.ts` to reflect the changes and added a comprehensive README for better script system documentation. Adjusted file paths accordingly for better organization.
Description
This implementation uses AI-generated metrics to gauge a rolling style and tone analysis as the user sends emails through Zero. This replaces the current
generateEmailBodylogic.Things to do: (Either in this PR or another)
Questions: (Also, for now or later PRs)
Ideas for later:
Holistic (out-of-scope) suggestions:
services(internal server-side services),lib(external apis), andutils(modular utility functions).v2easy to add then deprecate quickly.)_modulesfolders. This also makes things easy to find, quickly refactor, and branch off of for new version without causing unwanted breaking changes. Move UI components to@/componentswhen they be come widely reusable and hoisting up levels inappfolder isn't enough.How to test
bun db:pushto push the database changes.mail0_writing_style_matrixrecord in the database when switching style and tone in your tests.Suggested email tones:
Professional
Friendly
Concise & Direct
Persuasive / Value-Driven
Very Casual
Type of Change
Areas Affected
Testing Done
Security Considerations
For changes involving data or authentication:
Checklist
Additional Notes
Add any other context about the pull request here.
Screenshots/Recordings
Add screenshots or recordings here if applicable.
By submitting this pull request, I confirm that my contribution is made under the terms of the project's license.
Summary by CodeRabbit
New Features
Chores